package com.xishu.service.print.kitchen;

import com.alibaba.druid.sql.ast.statement.SQLIfStatement;
import com.xishu.bo.printer.PrinterItem;
import com.xishu.bo.printer.PrinterLine;
import com.xishu.client.PrinterClient;
import com.xishu.config.Config;
import com.xishu.config.Constant;
import com.xishu.entity.hardware.Printer;
import com.xishu.entity.oplog.OrderOpLog;
import com.xishu.entity.order.Order;
import com.xishu.entity.order.OrderItem;
import com.xishu.entity.shop.*;
import com.xishu.response.ResponseStatus;
import com.xishu.response.VerifyUtil;
import com.xishu.service.*;
import com.xishu.service.order.base.OrderService;
import com.xishu.service.print.CommonPrintService;
import com.xishu.util.AES;
import com.xishu.util.ClassUtil;
import com.xishu.util.DateUtil;
import com.xishu.util.Tools;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.xishu.config.Constant.SEND_KITCHEN;
import static com.xishu.config.Constant.SPECIAL_ITEM;

/**
 * 厨房打印服务
 */
public class KitchenService implements Tools {
    private static Logger logger = LoggerFactory.getLogger(KitchenService.class);
    private static KitchenService instance = new KitchenService();
    private CommonService commonService = CommonService.getInstance();
    private PrinterClient printerClient = PrinterClient.getInstance();
    private OrderService orderService = OrderService.getInstance();
    private LangService langService = LangService.getInstance();

    public static final int LINE_LENGTH = 48;
    private Config config = Config.getInstance();

    public static KitchenService getInstance() {
        return instance;
    }

    /**
     * 打印菜单,
     *
     * @param orderInDb
     * @param orderItemIdList
     */
    public void printerOrderItemList(Order orderInDb, List<Long> orderItemIdList) throws Exception {
        if (!config.canPrint()) {
            return;
        }

        //修改订单支付类型不打印
        if (Constant.isOrderPayModifyRequest()) {
            logger.info("its order pay modify request");
            return;
        }

        //复制一个，然后再处理
        orderInDb = (Order) ClassUtil.clone(orderInDb);
        commonService.dealDefaultValueWithAnnotation(orderInDb);
        orderInDb.getOrderItemDetailList().forEach(orderItem -> commonService.dealDefaultValueWithAnnotation(orderItem));

        //先过滤有哪些菜可以打印
        List<OrderItem> orderItemList = orderService.filterOrderItemList(orderInDb, orderItemIdList);
        List<Long> filterOrderItemIdList = orderItemList.stream().filter(orderItem -> orderItem.getCanSendToKitchen()).map(orderItem -> orderItem.getId()).collect(Collectors.toList());

        if (isEmpty(filterOrderItemIdList)) {
            logger.info("printer list is empty");
            return;
        }

        logger.info("will print shop {} order {}, filterOrderItemIdList {}", orderInDb.getShopId(), orderInDb.getId(), StringUtils.join(filterOrderItemIdList, ","));

        //查询所有的打印机
        List<Printer> allShopPrinterList = ShopService.getInstance().findAllShopPrinters(orderInDb.getShopId());
        for (Printer printer : allShopPrinterList) {
            //复制一份数据到打印机订单，以避免修改了以前的数据
            Order printOrder = (Order) ClassUtil.clone(orderInDb);

            //过滤出这次需要打印的菜品清单
            List<OrderItem> printerOrderItemList = getList(printOrder.getOrderItemDetailList()).stream().filter(p -> {
                return filterOrderItemIdList.contains(p.getId().longValue());
            }).collect(Collectors.toList());

            //过滤出哪些是要该打印机的菜品
            List<String> printerLabelList = printer.getPrinterLabelList();

            logger.info("printerLabelList is {}", StringUtils.join(printerLabelList, ","));

            if (isNotEmpty(printerLabelList)) {
                //过虑该打印机需要打印的菜
                printerOrderItemList = printerOrderItemList.stream().filter(orderItem -> {
                    return isItemContainThePrintLabel(printerLabelList, orderItem);
                }).collect(Collectors.toList());

                //将套餐里面的菜拆出来，然后同一个标签的，一起打印
                for (OrderItem orderItem : printerOrderItemList) {
                    filterValidLabelInSetMenuItem(printerLabelList, orderItem);
                }

                //发送厨房日志
                OrderOpLogService orderOpLogService = OrderOpLogService.getInstance();
                OrderOpLog orderOpLog = orderOpLogService.content(orderInDb, SEND_KITCHEN);
                orderOpLogService.realSendKitchenLog(orderInDb, filterOrderItemIdList, orderOpLog);

                printOrder.setOrderItemDetailList(printerOrderItemList);
                logger.info("printer order is {}", printOrder);
                //打印之后，还会修改余量
                sendOrderToKitchen(printOrder, printer.id);
            }
        }

    }

    /**
     * @param orderItem
     * @param printerLabelList
     * @return
     */
    public boolean isItemContainThePrintLabel(List<String> printerLabelList, OrderItem orderItem) {
        Long itemId = orderItem.getItemId();
        try {
            //特殊菜，单独处理,判断标签是否包含在打印机的标签上面
            if (equals(orderItem.getItemId(), SPECIAL_ITEM)) {

                return printerLabelList.contains(orderItem.getPrintLabel());
            }

            Item itemInDb = ItemService.getInstance().findItem(itemId);
            //单独的菜里面的标签包含了
            if (printerLabelList.contains(itemInDb.getPrintLabel())) {
                logger.info("contain the item label {}", itemInDb.getPrintLabel());
                return true;
            }

            if (!getBoolean(orderItem.getSetMenu())) {
                logger.info("not contain the order and its normal item");
                return false;
            }

            //这里一定是套餐
            //如果菜是按照套餐标签去打印，则不再判断了
            if (getBoolean(itemInDb.getSetMenuLabelEnable())) {
                return false;
            }

            List<SetMenuOneItem> setMenuOneItemList = orderItem.getSetMenuOneItemList();
            if (isEmpty(setMenuOneItemList)) {
                logger.info("set menu one item list is empty");
                return false;
            }

            return setMenuOneItemList.stream().filter(setMenuOneItem -> {
                List<Item> itemList = setMenuOneItem.getItemList();
                if (isEmpty(itemList)) {
                    return false;
                }

                //有一个菜在标签列表里面，就算存在
                return itemList.stream().filter(item -> isItemInPrinterList(item.getId(), printerLabelList)).findAny().isPresent();
            }).findAny().isPresent();
        } catch (Exception e) {
            logger.error("e", e);
            return false;
        }


    }


    /**
     * 将套餐里面的菜过滤一下，在打印机的标签里面的才保留，其它的删除掉
     *
     * @param printerLabelList
     * @param orderItem
     */
    public void filterValidLabelInSetMenuItem(List<String> printerLabelList, OrderItem orderItem) throws Exception {
        if (!getBoolean(orderItem.getSetMenu())) {
            logger.info("not the set menu item");
            return;
        }

        List<SetMenuOneItem> setMenuOneItemList = orderItem.getSetMenuOneItemList();
        if (isEmpty(setMenuOneItemList)) {
            return;
        }

        //如果是按照套餐标签打印，则不再过滤
        Long itemId = orderItem.getItemId();
        Item itemInDb = ItemService.getInstance().findItem(itemId);

        if (getBoolean(itemInDb.getSetMenuLabelEnable())) {
            logger.info("will print as set menu label");
            return;
        }

        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = setMenuOneItem.getItemList();
            if (isEmpty(itemList)) {
                logger.info("item list is empty");
                continue;
            }

            itemList = itemList.stream().filter(item -> isItemInPrinterList(item.getId(), printerLabelList)).collect(Collectors.toList());
            setMenuOneItem.setItemList(itemList);
        }

        setMenuOneItemList = setMenuOneItemList.stream().filter(setMenuOneItem -> {
            //有菜，并且选择的是正常菜，没有选择不加配
            return isNotEmpty(setMenuOneItem.getItemList()) && !ItemService.getInstance().isNoAdditionalInSetMenu(setMenuOneItem);
        }).collect(Collectors.toList());

        orderItem.setSetMenuOneItemList(setMenuOneItemList);
    }


    /**
     * 菜品是否包含在打印标签列表里面
     *
     * @param itemId
     * @param printerLabelList
     * @return
     */
    public boolean isItemInPrinterList(Long itemId, List<String> printerLabelList) {
        try {
            Item item = ItemService.getInstance().findItem(itemId);
            return printerLabelList.contains(item.getPrintLabel());
        } catch (Exception e) {
            logger.error("e");
            return false;
        }
    }

    /**
     * 合并菜
     *
     * @param order
     * @return
     */
    public List<OrderItem> combineOrderItemList(Order order) throws Exception {
        List<OrderItem> orderItemList = new ArrayList<>();

        for (OrderItem orderItem : order.getOrderItemDetailList()) {
            if (orderItemList.contains(orderItem)) {
                OrderItem orderItemFind = orderItemList.stream().filter(orderItemTmp -> equals(orderItemTmp, orderItem)).findAny().get();
                orderItemFind.setCount(orderItemFind.getCount() + orderItem.getCount());
            } else {
                orderItemList.add((OrderItem) ClassUtil.clone(orderItem));
            }
        }

        return orderItemList;
    }

    /**
     * 发送订单内容到厨房，第一次发送
     *
     * @param orderInDb
     */
    public boolean sendOrderToKitchen(Order orderInDb, Long printerId) throws Exception {
        //没有菜，直接返回
        if (isEmpty(orderInDb.getOrderItemDetailList())) {
            logger.info("{} has no order item detail list", printerId);
            return false;
        }

        //厨房里面的订单需要先合并，每一行的数据
        Order printerOrder = combineOrder(orderInDb);
        addRemarks(printerOrder);
        logger.info("combine order is {}", printerOrder);

        Printer kitchenPrinter = commonService.findEntity(printerId, Printer.class);

        //如果是一菜一单，那么需要多次打印
        if (getBoolean(kitchenPrinter.getOneItemOneOrder())) {
            logger.info("one item one order to kitchen");

            //一菜一单时，将一个套餐里面的菜拆分多个
            splitOrderItemList(printerOrder);

            //同菜一单，那么先合并，再打印
            if (kitchenPrinter.getSameItemOneTicket()) {
                List<OrderItem> orderItemList = combineOrderItemList(printerOrder);
                printerOrder.setOrderItemDetailList(orderItemList);
            }

            for (OrderItem orderItem : getList(printerOrder.getOrderItemDetailList())) {
                Order oneItemOneOrder = new Order();
                BeanUtils.copyProperties(printerOrder, oneItemOneOrder);

                List<OrderItem> orderItemList = new ArrayList<>();
                orderItemList.add(orderItem);
                oneItemOneOrder.setOrderItemDetailList(orderItemList);

                logger.info("will print order item is {}, itemId {}", orderItem.getId(), orderItem.getItemId());

                if (kitchenPrinter.getSameItemOneTicket() && orderItem.getCount() > 1) {
                    printOneOrderWhenSendToKitchen(oneItemOneOrder, kitchenPrinter, false);
                } else {
                    //有几份就打印几次
                    for (Integer i = 0; i < orderItem.getCount(); i++) {
                        //依次打印
                        printOneOrderWhenSendToKitchen(oneItemOneOrder, kitchenPrinter, true);
                    }
                }
            }
            return true;
        } else {
            //如果是整个发送
            logger.info("one order whole to kitchen");
            return printOneOrderWhenSendToKitchen(printerOrder, kitchenPrinter, false);
        }
    }

    /**
     * 本次要发送到厨房的数据先做合并
     *
     * @param reqOrder
     * @return
     */
    public Order combineOrder(Order reqOrder) {
        Order order = new Order();
        BeanUtils.copyProperties(reqOrder, order);
        order.setOrderItemDetailList(new ArrayList<>());

        for (OrderItem orderItem : getList(reqOrder.getOrderItemDetailList())) {
            //如果是特别菜，直接添加
            if (equals(orderItem.getItemId(), SPECIAL_ITEM)) {
                order.getOrderItemDetailList().add(orderItem);
                continue;
            }

            //没有包含
            if (!order.getOrderItemDetailList().contains(orderItem)) {
                order.getOrderItemDetailList().add(orderItem);
            } else {
                //已经有了，先找出来，然后更新数量
                Optional<OrderItem> itemOptional = order.getOrderItemDetailList().stream().filter(p -> p.equals(orderItem)).findFirst();
                OrderItem findOrderItem = itemOptional.get();
                findOrderItem.setCount(findOrderItem.getCount() + orderItem.getCount());
            }
        }

        return order;
    }

    /**
     * 将订单里面套餐里面的菜拆分成多个
     *
     * @param order
     */
    public void splitOrderItemList(Order order) throws Exception {
        List<OrderItem> orderItemDetailList = getList(order.getOrderItemDetailList()).stream().filter(p -> getBoolean(p.getSetMenu())).collect(Collectors.toList());
        if (isEmpty(orderItemDetailList)) {
            logger.info("order item detail list is empty");
            return;
        }

        List<OrderItem> orderItemList = new ArrayList<>();

        for (OrderItem orderItem : orderItemDetailList) {
            //如果是套餐标签打印，则不用拆分
            Long itemId = orderItem.getItemId();
            if (getLong(itemId) == 0L) {
                continue;
            }

            Item itemInDb = ItemService.getInstance().findItem(itemId);
            if (getBoolean(itemInDb.getSetMenuLabelEnable())) {
                logger.info("set menu label enable {}", itemId);
                orderItemList.add(orderItem);
                continue;
            }

            List<SetMenuOneItem> setMenuOneItemList = getList(orderItem.getSetMenuOneItemList());
            for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
                try {
                    List<Item> itemList = setMenuOneItem.getItemList();
                    for (Item item : itemList) {
                        if (getLong(item.getId()) == 0L) {
                            logger.info("item id is 0");
                            continue;
                        }

                        OrderItem cloneOrderItem = (OrderItem) ClassUtil.clone(orderItem);
                        SetMenuOneItem cloneSetMenuOneItem = (SetMenuOneItem) ClassUtil.clone(setMenuOneItem);
                        cloneOrderItem.setSetMenuOneItemList(Arrays.asList(cloneSetMenuOneItem));
                        cloneSetMenuOneItem.setItemList(Arrays.asList(item));
                        orderItemList.add(cloneOrderItem);
                    }
                } catch (Exception e) {
                    logger.error("e", e);
                }
            }
        }

        //再加上普通规格菜
        List<OrderItem> commonItemList = getList(order.getOrderItemDetailList()).stream().filter(p -> !getBoolean(p.getSetMenu())).collect(Collectors.toList());
        if (isNotEmpty(commonItemList)) {
            orderItemList.addAll(commonItemList);
        }

        order.setOrderItemDetailList(orderItemList);
    }

    public boolean printOneOrderWhenSendToKitchen(Order order, Printer kitchenPrinter, boolean oneItemOneOrder) throws Exception {
        Boolean zh = commonService.isZh(kitchenPrinter.getLang());

        VerifyUtil.verify(() -> kitchenPrinter != null, ResponseStatus.KITCHEN_PRINTER__NOT_CONFIG);
        String printerSn = AES.decrypt(kitchenPrinter.getPrinterSn());
        Shop shop = ShopService.getInstance().findShopById(order.getShopId());

        //生成打印字符串
        ArrayList<PrinterLine> printerLines = new ArrayList<>();

        if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT || order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
            if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
                //foodpanda
                logger.info("will print foodpanda");
                printerLines.add(printerClient.newLine(CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out_plat(zh)), true, true));
            } else {
                //外卖
                logger.info("will printer take out");
                printerLines.add(printerClient.newLine(CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out(zh)), true, true));
            }
        } else if (isEmpty(order.getCode())) {
            //堂食
            logger.info("will printer tang shi");
            printerLines.add(printerClient.newLine(config.label_tang_shi(zh), true, true));
        } else {
            logger.info("will printer code");
            PrinterLine printerLine = printerClient.directLine();
            PrinterItem printerItem = printerLine.getItemList().get(0);
            String code = order.getCode();

            if (order.getShowNo() != null) {
                code = order.getCode() + "-" + order.getShowNo();
            }

            code = printerClient.appendCenter(code);
            code = printerClient.appendBold(code);
            code = printerClient.appendDouble(code);
            printerItem.setContent(code);
            printerLines.add(printerLine);
        }

        //每日单号
        PrinterLine orderNoLabelLine = new PrinterLine();
        PrinterItem orderNoLabelItem = new PrinterItem();
        String perDayOrderNo = null;
        if (getBoolean(zh)) {
            perDayOrderNo = config.label_per_day_order(zh) + "：";
        } else {
            perDayOrderNo = config.label_per_day_order(zh) + ":";
        }

        orderNoLabelItem.setContent(perDayOrderNo);
        orderNoLabelItem.setBold(true);
        orderNoLabelItem.setDoubleShow(true);
        orderNoLabelLine.add(orderNoLabelItem);

        PrinterItem orderNoItem = new PrinterItem();
        orderNoItem.setContent(order.getOrderNo() + "");
        orderNoItem.setBold(true);
        orderNoItem.setDoubleShow(true);
        orderNoLabelLine.add(orderNoItem);

        printerLines.add(orderNoLabelLine);

        //订单优先的时候，如果是加菜的订单，如果添加加菜项
        if (getBoolean(shop.getShopConfig().getOrderFirst()) && isNotEmpty(order.getSendPrinterList())) {
            logger.info("will add item label");
            printerLines.add(printerClient.newLine(printBlackGround(config.label_add_item(zh)), true, null));
        }

        logger.info("kitchen one order one  printer");
        //一菜一单不用打印数量
        if (oneItemOneOrder) {
            //数量,标签
            PrinterLine titleLine = new PrinterLine();
            titleLine.setDirect(true);
            PrinterItem itemNameLabelItem = new PrinterItem();
            StringBuilder sb = new StringBuilder();
            sb.append(config.label_name(zh));
            itemNameLabelItem.setContent(sb.toString());
            titleLine.add(itemNameLabelItem);

            printerLines.add(titleLine);
        } else {
            //数量,标签
            PrinterLine titleLine = new PrinterLine();
            titleLine.setDirect(true);
            PrinterItem countLabelItem = new PrinterItem();
            countLabelItem.setContent(config.label_count(zh));
            titleLine.add(countLabelItem);

            //名称,左边占用12位
            PrinterItem itemNameLabelItem = new PrinterItem();
            StringBuilder sb = new StringBuilder();
            //计算空格
            String labelName = config.label_name(zh);
            int spaceSize = (12 - printerClient.getGbkLength(labelName));

            for (int i = 0; i < spaceSize; i++) {
                sb.append(" ");
            }

            sb.append(labelName);

            itemNameLabelItem.setContent(sb.toString());
            titleLine.add(itemNameLabelItem);

            printerLines.add(titleLine);
        }

        //分隔符
        printerLines.add(printerClient.printSeparator());


        //打印菜
        //*********************************************************发送厨房打印菜的内容******************************************************************************
        logger.info("print order item details");
        List<PrinterLine> printerLineList = printerKitchenOrderItemList(order, oneItemOneOrder, zh);
        //去掉首尾的空行，如果有的话
        printerClient.removeFirstEmptyLine(printerLineList);
        printerClient.removeLastEmptyLine(printerLineList);
        printerClient.removeLastEmptyLine(printerLineList);
        printerLines.addAll(printerLineList);
        //*********************************************************发送厨房打印菜的内容******************************************************************************

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //添加备注
        if (isNotEmpty(order.getRemarks())) {
            StringBuilder remarks = new StringBuilder();
            remarks.append(config.label_remarks(zh));
            remarks.append(order.getRemarks());
            PrinterLine printerLine = printerClient.newLine(printerClient.appendDouble(remarks));
            printerLines.add(printerLine);
        }

        //添加下单时间
        String createTime = config.label_order_time(zh) + DateUtil.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
        printerLines.add(printerClient.newLine(createTime, null, null));

        //空两行
        printerClient.emptyLine();
        printerClient.emptyLine();

        //如果是加菜的订单，如果添加加菜项
        if (getBoolean(shop.getShopConfig().getOrderFirst()) && isNotEmpty(order.getSendPrinterList())) {
            printerLines.add(printerClient.newLine(printBlackGround(config.label_add_item(zh)), true, null));
        }

        //再打印堂食或者桌号
        String content = null;
        if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT || order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
            //foodpanda
            if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
                content = CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out_plat_bottom(zh));
            } else {
                //外卖
                content = CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out_bottom(zh));
            }
        } else if (isEmpty(order.getCode())) {
            content = config.label_tang_shi(zh);
        } else {
            if (order.getShowNo() != null) {
                content = order.getCode() + "-" + order.getShowNo();
            } else {
                content = order.getCode();
            }
        }

        printerLines.add(printerClient.emptyLine());
        boolean customizedTakeoutOrder = orderService.isCustomizedTakeoutOrder(order);
        //打印结束的三个单词
        if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT_PLAT) {
            PrinterLine endLine = new PrinterLine();
            endLine.setDirect(true);
            PrinterItem endItem1 = new PrinterItem();
            int contentSize = PrinterClient.getInstance().getGbkLength(content);
            int addSpace = (LINE_LENGTH - contentSize * 3) / 2;
            endItem1.setContent("<L><BOLD>" + content + "<L></BOLD>");
            PrinterItem endItem2 = new PrinterItem();
            StringBuilder centerContentBuilder = new StringBuilder();
            centerContentBuilder.append("<L><BOLD>");

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append(content);

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append("<L></BOLD>");

            endItem2.setContent(centerContentBuilder.toString());
            PrinterItem endItem3 = new PrinterItem();
            endItem3.setContent("<L><BOLD>" + content + "<L></BOLD>");

            endLine.add(endItem1);
            endLine.add(endItem2);
            endLine.add(endItem3);

            printerLines.add(endLine);

        } else {
            //打印结束的三个单词
            if (!customizedTakeoutOrder) {
                PrinterLine endLine = new PrinterLine();
                endLine.setDirect(true);
                PrinterItem endItem1 = new PrinterItem();
                int contentSize = PrinterClient.getInstance().getGbkLength(content);
                int addSpace = ((LINE_LENGTH / 2) - contentSize * 3) / 2;
                endItem1.setContent("<B>" + content + "</B>");
                PrinterItem endItem2 = new PrinterItem();
                StringBuilder centerContentBuilder = new StringBuilder();
                centerContentBuilder.append("<B>");

                for (int i = 0; i < addSpace; i++) {
                    centerContentBuilder.append(" ");
                }

                centerContentBuilder.append(content);

                for (int i = 0; i < addSpace; i++) {
                    centerContentBuilder.append(" ");
                }

                centerContentBuilder.append("</B>");

                endItem2.setContent(centerContentBuilder.toString());
                PrinterItem endItem3 = new PrinterItem();
                endItem3.setContent("<B>" + content + "</B>");

                endLine.add(endItem1);
                endLine.add(endItem2);
                endLine.add(endItem3);

                printerLines.add(endLine);
            } else {
                PrinterLine endLine = new PrinterLine();
                endLine.setDirect(true);
                PrinterItem endItem1 = new PrinterItem();
                int contentSize = PrinterClient.getInstance().getGbkLength(content);
                int addSpace = (LINE_LENGTH - contentSize * 3) / 2;
                endItem1.setContent("<L><BOLD>" + content + "</BOLD></L>");
                PrinterItem endItem2 = new PrinterItem();
                StringBuilder centerContentBuilder = new StringBuilder();
                centerContentBuilder.append("<L><BOLD>");

                for (int i = 0; i < addSpace; i++) {
                    centerContentBuilder.append(" ");
                }

                centerContentBuilder.append(content);

                for (int i = 0; i < addSpace; i++) {
                    centerContentBuilder.append(" ");
                }

                centerContentBuilder.append("</BOLD></L>");

                endItem2.setContent(centerContentBuilder.toString());
                PrinterItem endItem3 = new PrinterItem();
                endItem3.setContent("<L><BOLD>" + content + "</BOLD></L>");

                endLine.add(endItem1);
                endLine.add(endItem2);
                endLine.add(endItem3);

                printerLines.add(endLine);
            }
        }

        //打印结束的三个单词
        return printerClient.printList(printerLines, printerSn, kitchenPrinter.getId());
    }

    public boolean newPrintOneOrderWhenSendToKitchen(Order order, Printer kitchenPrinter) throws Exception {
        Boolean zh = commonService.isZh(kitchenPrinter.getLang());

        VerifyUtil.verify(() -> kitchenPrinter != null, ResponseStatus.KITCHEN_PRINTER__NOT_CONFIG);
        String printerSn = AES.decrypt(kitchenPrinter.getPrinterSn());
        Shop shop = ShopService.getInstance().findShopById(order.getShopId());

        //生成打印字符串
        ArrayList<PrinterLine> printerLines = new ArrayList<>();

        if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT) {
            //外卖
            logger.info("will printer take out");
            printerLines.add(printerClient.newLine(CommonPrintService.getInstance().getTakeoutLabel(order, zh, config.label_take_out(zh)), true, true));
        } else if (isEmpty(order.getCode())) {
            //堂食
            logger.info("will printer tang shi");
            printerLines.add(printerClient.newLine(config.label_tang_shi(zh), true, true));
        } else {
            logger.info("will printer code");
            PrinterLine printerLine = printerClient.directLine();
            PrinterItem printerItem = printerLine.getItemList().get(0);
            String code = order.getCode();

            if (order.getShowNo() != null) {
                code = order.getCode() + "-" + order.getShowNo();
            }

            code = printerClient.appendCenter(code);
            code = printerClient.appendBold(code);
            code = printerClient.appendDouble(code);
            printerItem.setContent(code);
            printerLines.add(printerLine);
        }

        //每日单号
        PrinterLine orderNoLabelLine = new PrinterLine();
        PrinterItem orderNoLabelItem = new PrinterItem();
        String perDayOrderNo = null;
        if (getBoolean(zh)) {
            perDayOrderNo = config.label_per_day_order(zh) + "：";
        } else {
            perDayOrderNo = config.label_per_day_order(zh) + ":";
        }

        orderNoLabelItem.setContent(perDayOrderNo);
        orderNoLabelItem.setBold(true);
        orderNoLabelItem.setDoubleShow(true);
        orderNoLabelLine.add(orderNoLabelItem);

        PrinterItem orderNoItem = new PrinterItem();
        orderNoItem.setContent(order.getOrderNo() + "");
        orderNoItem.setBold(true);
        orderNoItem.setDoubleShow(true);
        orderNoLabelLine.add(orderNoItem);

        printerLines.add(orderNoLabelLine);

        //订单优先的时候，如果是加菜的订单，如果添加加菜项
        if (getBoolean(shop.getShopConfig().getOrderFirst()) && isNotEmpty(order.getSendPrinterList())) {
            logger.info("will add item label");
            printerLines.add(printerClient.newLine(printBlackGround(config.label_add_item(zh)), true, null));
        }

        logger.info("kitchen one order one  printer");
        //一菜一单不用打印数量
        if (getBoolean(kitchenPrinter.getOneItemOneOrder())) {
            //数量,标签
            PrinterLine titleLine = new PrinterLine();
            titleLine.setDirect(true);
            PrinterItem itemNameLabelItem = new PrinterItem();
            StringBuilder sb = new StringBuilder();
            sb.append(config.label_name(zh));
            itemNameLabelItem.setContent(sb.toString());
            titleLine.add(itemNameLabelItem);

            printerLines.add(titleLine);
        } else {
            //数量,标签
            PrinterLine titleLine = new PrinterLine();
            titleLine.setDirect(true);
            PrinterItem countLabelItem = new PrinterItem();
            countLabelItem.setContent(config.label_count(zh));
            titleLine.add(countLabelItem);

            //名称,左边占用12位
            PrinterItem itemNameLabelItem = new PrinterItem();
            StringBuilder sb = new StringBuilder();
            //计算空格
            String labelName = config.label_name(zh);
            int spaceSize = (12 - printerClient.getGbkLength(labelName));

            for (int i = 0; i < spaceSize; i++) {
                sb.append(" ");
            }

            sb.append(labelName);

            itemNameLabelItem.setContent(sb.toString());
            titleLine.add(itemNameLabelItem);

            printerLines.add(titleLine);
        }

        //分隔符
        printerLines.add(printerClient.printSeparator());


        //打印菜
        //*********************************************************发送厨房打印菜的内容******************************************************************************
        logger.info("print order item details");
        List<PrinterLine> printerLineList = printerKitchenOrderItemList(order, getBoolean(kitchenPrinter.getOneItemOneOrder()), zh);
        //去掉最后的空行
        printerClient.removeLastEmptyLine(printerLineList);
        printerLines.addAll(printerLineList);
        //*********************************************************发送厨房打印菜的内容******************************************************************************

        //分隔符
        printerLines.add(printerClient.printSeparator());

        //添加备注
        if (isNotEmpty(order.getRemarks())) {
            StringBuilder remarks = new StringBuilder();
            remarks.append(config.label_remarks(zh));
            remarks.append(order.getRemarks());
            PrinterLine printerLine = printerClient.newLine(printerClient.appendDouble(remarks));
            printerLines.add(printerLine);
        }

        //添加下单时间
        String createTime = config.label_order_time(zh) + DateUtil.format(System.currentTimeMillis(), "yyyy-MM-dd HH:mm:ss");
        printerLines.add(printerClient.newLine(createTime, null, null));

        //空两行
        printerClient.emptyLine();
        printerClient.emptyLine();

        //如果是加菜的订单，如果添加加菜项
        if (getBoolean(shop.getShopConfig().getOrderFirst()) && isNotEmpty(order.getSendPrinterList())) {
            printerLines.add(printerClient.newLine(printBlackGround(config.label_add_item(zh)), true, null));
        }

        //再打印堂食或者桌号
        String content = null;
        if (order.getOrderType() == Constant.ORDER_TYPE_TAKE_OUT) {
            //外卖
            content = config.label_take_out_bottom(zh);
        } else if (isEmpty(order.getCode())) {
            content = config.label_tang_shi(zh);
        } else {
            if (order.getShowNo() != null) {
                content = order.getCode() + "-" + order.getShowNo();
            } else {
                content = order.getCode();
            }
        }

        printerLines.add(printerClient.emptyLine());
        boolean customizedTakeoutOrder = orderService.isCustomizedTakeoutOrder(order);

        //打印结束的三个单词
        if (!customizedTakeoutOrder) {
            PrinterLine endLine = new PrinterLine();
            endLine.setDirect(true);
            PrinterItem endItem1 = new PrinterItem();
            int contentSize = PrinterClient.getInstance().getGbkLength(content);
            int addSpace = ((LINE_LENGTH / 2) - contentSize * 3) / 2;
            endItem1.setContent("<B>" + content + "</B>");
            PrinterItem endItem2 = new PrinterItem();
            StringBuilder centerContentBuilder = new StringBuilder();
            centerContentBuilder.append("<B>");

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append(content);

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append("</B>");

            endItem2.setContent(centerContentBuilder.toString());
            PrinterItem endItem3 = new PrinterItem();
            endItem3.setContent("<B>" + content + "</B>");

            endLine.add(endItem1);
            endLine.add(endItem2);
            endLine.add(endItem3);

            printerLines.add(endLine);
        } else {
            PrinterLine endLine = new PrinterLine();
            endLine.setDirect(true);
            PrinterItem endItem1 = new PrinterItem();
            int contentSize = PrinterClient.getInstance().getGbkLength(content);
            int addSpace = (LINE_LENGTH - contentSize * 3) / 2;
            endItem1.setContent("<L><BOLD>" + content + "</BOLD></L>");
            PrinterItem endItem2 = new PrinterItem();
            StringBuilder centerContentBuilder = new StringBuilder();
            centerContentBuilder.append("<L><BOLD>");

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append(content);

            for (int i = 0; i < addSpace; i++) {
                centerContentBuilder.append(" ");
            }

            centerContentBuilder.append("</BOLD></L>");

            endItem2.setContent(centerContentBuilder.toString());
            PrinterItem endItem3 = new PrinterItem();
            endItem3.setContent("<L><BOLD>" + content + "</BOLD></L>");

            endLine.add(endItem1);
            endLine.add(endItem2);
            endLine.add(endItem3);

            printerLines.add(endLine);
        }

        return printerClient.printList(printerLines, printerSn, kitchenPrinter.getId());
    }

    /**
     * 打印黑底白字
     *
     * @param content
     * @return
     */
    public String printBlackGround(String content) {
        byte[] spaces = new byte[3];
        spaces[0] = 0x1d;
        spaces[1] = 0x42;
        spaces[2] = 0x01;
        String ls = new String(spaces);//开始
        byte[] spacee = new byte[2];
        spacee[0] = 0x1d;
        spacee[1] = 0x42;
        String le = new String(spacee) + "0";//结束

        //补齐空格
        int spaceLength = (PrinterClient.LINE_LENGTH / 2 - printerClient.getGbkLength(content)) / 2;
        String spaceList = printerClient.generateSpace(spaceLength);
        content = String.format("%s%s%s", spaceList, content, spaceList);

        content = ls + content + le;
        return "<B>" + content + "</B>";
    }

    /**
     * 将订单里面的每一行打印出来
     *
     * @param order
     * @return
     */
    private List<PrinterLine> printerKitchenOrderItemList(Order order, boolean oneItemOneOrder, boolean zh) throws Exception {
        //一菜一单模式，不显示数量，只显示菜品以及规格
        if (oneItemOneOrder) {
            logger.info("one item one order in kitchen order {}", order.getId());
            return printOneItemOneOrder_kitchen(order, zh);
        }

        logger.info("whole order order {}", order.getId());
        return printWholeOrderSendToKitchen(order, zh);
    }

    /**
     * 打印一菜一单
     *
     * @param order
     * @param zh
     * @return
     * @throws Exception
     */
    private ArrayList<PrinterLine> printOneItemOneOrder_kitchen(Order order, boolean zh) throws Exception {
        ArrayList<PrinterLine> printerLineList = new ArrayList<>();

        List<OrderItem> orderItemDetailList = getList(order.getOrderItemDetailList());
        OrderItem orderItem = orderItemDetailList.get(0);

        Item setMenuItemInDb = null;

        if (getLong(orderItem.getItemId()) > 0) {
            setMenuItemInDb = ItemService.getInstance().findItem(orderItem.getItemId());
        }

        //名称
        StringBuilder itemNameBuilder = new StringBuilder();

        //构建打印名称
        String itemPrintName = CommonPrintService.getInstance().getPrintItemName(zh, orderItem);

        //前面加4个空格,也就是2个汉字的距离
        itemNameBuilder.append(itemPrintName);

        //加了外卖标记，标粗
        if (getBoolean(orderItem.getTakeout()) && !orderService.isTakeoutOrder(order)) {
            itemNameBuilder.append("(" + config.label_take_out(zh) + ")");
        }

        if (setMenuItemInDb == null || !getBoolean(setMenuItemInDb.getNotPrintItemName())) {
            List<String> nameList = null;

            nameList = printerClient.getStringList(itemNameBuilder.toString(), LINE_LENGTH / 2, zh);

            //一菜一单不再空行
            for (String name : nameList) {
                PrinterLine itemNameLine = printerClient.directLine();
                itemNameLine.setDirect(true);
                itemNameLine.getPrinterItem().setContent(printerClient.appendDouble(name));
                printerLineList.add(itemNameLine);
            }
        }

        if (config.kitchenReceiptSpacing()) {
            printerLineList.add(printerClient.emptyLine());
        }

        //添加规格项
        //如果还有规格项，再依次添加规格项
        if (isNotEmpty(orderItem.getItemDetailList())) {
            logger.info("print one item one order with normal item item");
            printerLineList.addAll(printOneItemOneOrderDetail(orderItem, zh));
        } else if (getBoolean(orderItem.getSetMenu())) {
            logger.info("print one item one order with set menu item");
            boolean addSetMenuItemTakeoutFlag = isAddSetMenuItemTakeoutFlag(order, orderItem, setMenuItemInDb);

            printerLineList.addAll(printNew1Item1OrderDetailInSetMenu(orderItem, zh, addSetMenuItemTakeoutFlag));
        }

        return printerLineList;
    }

    private boolean isAddSetMenuItemTakeoutFlag(Order order, OrderItem orderItem) {
        if (getLong(orderItem.getItemId()) <= 0) {
            return false;
        }

        try {
            Item itemInDb = ItemService.getInstance().findItem(orderItem.getItemId());
            return isAddSetMenuItemTakeoutFlag(order, orderItem, itemInDb);
        } catch (Exception e) {
            logger.error("e", e);
            return false;
        }
    }

    private boolean isAddSetMenuItemTakeoutFlag(Order order, OrderItem orderItem, Item setMenuItemInDb) {
        if (setMenuItemInDb == null) {
            return false;
        }

        if (!getBoolean(setMenuItemInDb.getSetMenu())) {
            logger.info("isAddSetMenuItemTakeoutFlag {} not set menu", setMenuItemInDb.getId());
            return false;
        }

        boolean addSetMenuItemTakeoutFlag = false;

        if (getBoolean(orderItem.getTakeout()) && !orderService.isTakeoutOrder(order) && getBoolean(setMenuItemInDb.getNotPrintItemName())) {
            addSetMenuItemTakeoutFlag = true;
        }

        logger.info("addSetMenuItemTakeoutFlag {}", addSetMenuItemTakeoutFlag);
        return addSetMenuItemTakeoutFlag;
    }

    /**
     * 发送到厨房时的菜品打印
     *
     * @param order
     * @param zh
     * @return
     */
    private ArrayList<PrinterLine> printWholeOrderSendToKitchen(Order order, boolean zh) throws Exception {
        //其它模式
        ArrayList<PrinterLine> printerLineList = new ArrayList<>();

        for (OrderItem orderItem : getList(order.getOrderItemDetailList())) {
            PrinterLine orderItemLine = new PrinterLine();
            orderItemLine.setDirect(true);
            //数量
            PrinterItem countItem = new PrinterItem();

            String countString = " " + orderItem.getCount();
            countString = printerClient.appendDouble(countString);
            countItem.setContent(countString);
            orderItemLine.add(countItem);

            //名称
            PrinterItem itemNameItem = new PrinterItem();

            Long setMenuItemId = orderItem.getItemId();
            Item setMenuItem = null;

            if (getLong(setMenuItemId) > 0) {
                setMenuItem = ItemService.getInstance().findItem(setMenuItemId);
            }

            String printItemName = null;
            boolean notPrintItemName = isNotPrintItemNameFromItem(setMenuItem);

            //只有套餐才不打印
            if (notPrintItemName) {
                //打印第一个菜的名称
                Item item = orderItem.getSetMenuOneItemList().get(0).getItemList().get(0);
                Item itemInDb = ItemService.getInstance().findItem(item.getId());
                //再加两个空格
                printItemName = CommonPrintService.getInstance().getItemPrintName(itemInDb, zh);
            } else {
                printItemName = CommonPrintService.getInstance().getPrintItemName(zh, orderItem);
            }


            //加了外卖标记，标粗
            if (getBoolean(orderItem.getTakeout()) && !orderService.isTakeoutOrder(order)) {
                StringBuilder itemNameBuilder = new StringBuilder();
                //计算空格
                int countRealSize = (" " + orderItem.getCount()).length();
                //空格占用8个字符的长度，double过后，整个实际占用16个字条的长度
                int countSize = 8;
                int spaceSize = countSize - countRealSize;

                List<String> itemNameList = getPrintItemName(zh, printItemName, countSize);

                //如果是第一行，需要添加数字
                itemNameBuilder.append(printerClient.appendDouble(printerClient.generateSpace(spaceSize)));
                printerLineList.add(printerClient.newLine(printerClient.appendDouble(" " + orderItem.getCount() + printerClient.generateSpace(spaceSize) + itemNameList.get(0))));


                if (itemNameList.size() >= 2) {
                    for (String name : itemNameList.subList(1, itemNameList.size())) {
                        PrinterLine printerLine = printerClient.newLine(printerClient.appendDouble(printerClient.generateSpace(countSize) + name));
                        printerLineList.add(printerLine);
                    }
                }
            } else {
                //空格占用8个字符的长度，double过后，整个实际占用16个字条的长度
                int countSize = 8;
                //前面两个空格， 再加上数量
                int countRealSize = (" " + orderItem.getCount()).length();

                //左边12个减一半为6，再减去空格以及数量占用的宽度
                int spaceSize = countSize - countRealSize;
                //多减两个空格，也就是一个字的显示长度，以避免换行
                List<String> itemNameList = printerClient.getStringList(printItemName, (LINE_LENGTH) / 2 - countSize, zh);
                StringBuilder itemNameBuilder = new StringBuilder();
                itemNameBuilder.append(printerClient.appendDouble(printerClient.generateSpace(spaceSize)));

                if (isNotEmpty(itemNameList)) {
                    itemNameBuilder.append(printerClient.appendDouble(itemNameList.get(0)));
                }
                itemNameItem.setContent(itemNameBuilder.toString());

                logger.info("item name is {}", itemNameItem.getContent());
                orderItemLine.add(itemNameItem);
                printerLineList.add(orderItemLine);
                logger.info("will add order detail");

                if (isNotEmpty(itemNameList)) {
                    //如果出现了多行，那么添加多行
                    for (String itemLeftName : itemNameList.subList(1, itemNameList.size())) {
                        //固定6个空格
                        PrinterLine printerLine = printerClient.newLine(printerClient.appendDouble(printerClient.generateSpace(countSize) + itemLeftName));
                        printerLineList.add(printerLine);
                    }
                }
            }

            if (config.kitchenReceiptSpacing()) {
                printerLineList.add(printerClient.emptyLine());
            }

            //如果还有规格项，再依次添加规格项
            if (isNotEmpty(orderItem.getItemDetailList())) {
                Long itemId = orderItem.getItemId();
                logger.info("print whole order with normal item to kitchen , item id {}", itemId);
                List<PrinterLine> itemDetailWhenSendToKitchen = printItemDetail_Kitchen(orderItem.getItemDetailList(), zh);
                printerLineList.addAll(itemDetailWhenSendToKitchen);
            } else if (getBoolean(orderItem.getSetMenu())) {
                //还是个套餐，那么处理套餐的样式
                Long itemId = orderItem.getItemId();
                boolean addSetMenuItemTakeoutFlag = isAddSetMenuItemTakeoutFlag(order, orderItem);
                logger.info("print whole order with set menu item to kitchen , item id {}", itemId);
                List<PrinterLine> itemDetailWhenSendToKitchen = printerSetMenuWhenSendToKitchen(orderItem, zh, notPrintItemName, addSetMenuItemTakeoutFlag);
                printerLineList.addAll(itemDetailWhenSendToKitchen);
            }
        }

        return printerLineList;
    }

    /**
     * 获取打印名称
     *
     * @param zh
     * @param printItemName
     * @return
     */
    private List<String> getPrintItemName(boolean zh, String printItemName, int countSize) {
        if (isEmpty(printItemName)) {
            return new ArrayList<>();
        }

        printItemName = printItemName + String.format("(%s)", config.label_take_out(zh));

        //因为打印的时候，会显示双倍，所以这里先除以2，再减
        return printerClient.getStringList(printItemName, (LINE_LENGTH) / 2 - countSize, zh);
    }

    private boolean isNotPrintItemNameFromItem(Item setMenuItem) {
        boolean notPrintItemName = false;

        if (setMenuItem != null) {
            notPrintItemName = getBoolean(setMenuItem.getNotPrintItemName());
        }

        return notPrintItemName;
    }


    /**
     * 一菜一单的细节
     *
     * @param orderItem
     * @param zh
     * @return
     */
    private List<PrinterLine> printOneItemOneOrderDetail(OrderItem orderItem, boolean zh) throws Exception {
        List<ItemDetail> itemDetailList = orderItem.getItemDetailList();
        Long itemId = orderItem.getItemId();

        logger.info("add item detail {} in one item one order", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        int appendSpaceSize = 4;

        itemDetailList.stream().forEach(itemDetail -> {
            //横版打印
            if (!getBoolean(itemDetail.getVerticalPrint())) {
                PrinterLine printerLine = printerClient.directLine();

                PrinterItem printerItem = new PrinterItem();
                List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    return nameAndPriceName;
                }).collect(Collectors.toList());

                String itemDetailContent = StringUtils.join(nameList, ", ");

                //每个细节占用的空格数
                int oneItemDetailLength = (LINE_LENGTH / 2 - appendSpaceSize);

                List<String> detailContentList = printerClient.getStringList(itemDetailContent, oneItemDetailLength, zh);

                List<String> contentList = detailContentList.stream().map(oneDetailContent -> {
                    logger.info("oneDetailContent is {}", oneDetailContent.trim());
                    //空6个空格,3个汉字的距离
                    return printerClient.generateSpace(appendSpaceSize) + oneDetailContent.trim();
                }).collect(Collectors.toList());

                String content = StringUtils.join(contentList, "<BR>");

                printerItem.setContent(printerClient.appendDouble(content));
                printerLine.add(printerItem);

                printerLineList.add(printerLine);
            } else {
                //竖版打印
                PrinterLine printerLine = printerClient.directLine();

                PrinterItem printerItem = new PrinterItem();

                //每个细节占用的空格数
                int oneItemDetailLength = (LINE_LENGTH / 2 - appendSpaceSize);

                List<String> contentList = itemDetail.getNameAndPriceList().stream().flatMap(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    logger.info("nameAndPriceName is {}", nameAndPriceName.trim());
                    //空6个空格,3个汉字的距离
                    List<String> detailContentList = printerClient.getStringList(nameAndPriceName, oneItemDetailLength, zh);
                    return detailContentList.stream().map(p -> printerClient.generateSpace(appendSpaceSize) + nameAndPriceName.trim());
                }).collect(Collectors.toList());

                String content = StringUtils.join(contentList, "<BR>");

                printerItem.setContent(printerClient.appendDouble(content));
                printerLine.add(printerItem);

                printerLineList.add(printerLine);
            }

            if (config.kitchenReceiptSpacing()) {
                printerLineList.add(printerClient.emptyLine());
            }

        });

        return printerLineList;
    }

    /**
     * 新版本的一菜一单套餐打印
     * <p>
     * 套餐的名称在外层已经打了
     * 内层的套餐需要带名称，以及规格项来打印
     *
     * @param orderItem
     * @param zh
     * @return
     */
    public List<PrinterLine> printNew1Item1OrderDetailInSetMenu(OrderItem orderItem, boolean zh, boolean addSetMenuItemTakeoutFlag) throws Exception {
        List<SetMenuOneItem> setMenuOneItemList = getList(orderItem.getSetMenuOneItemList());
        if (isEmpty(setMenuOneItemList)) {
            logger.info("set menu one item list is empty");
            return new ArrayList<>();
        }

        Item setMenuItemInDb = ItemService.getInstance().findItem(orderItem.getItemId());
        boolean notPrintItemName = getBoolean(setMenuItemInDb.getNotPrintItemName());

        List<PrinterLine> printerLineList = new ArrayList<>();
        for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
            List<Item> itemList = getList(setMenuOneItem.getItemList());

            itemList = itemList.stream().filter(p -> p.getId() != 0).collect(Collectors.toList());

            //套餐里面的菜，均由前端传过来了
            for (Item item : itemList) {
                int prefixSpaceSize = getPrefixSpaceSize(notPrintItemName);

                //先添加名称
                String itemName = CommonPrintService.getInstance().getItemPrintName(ItemService.getInstance().findItem(item.getId()), zh);
                itemName = CommonPrintService.getInstance().getItemNameWithCount(itemName, item);

                if (addSetMenuItemTakeoutFlag) {
                    itemName = itemName + "(" + config.label_take_out(zh) + ")";
                }

                //因为是放大了，长度只有2分之1
                List<String> nameList = printerClient.getStringList(itemName, (LINE_LENGTH / 2 - prefixSpaceSize), zh);
                for (String name : nameList) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(printerClient.generateSpace(prefixSpaceSize));
                    sb.append(name);
                    printerLineList.add(printerClient.newLine(printerClient.appendDouble(sb.toString())));
                }
                //打印完菜品名字就空一行
                if (config.kitchenReceiptSpacing()) {
                    printerLineList.add(printerClient.emptyLine());
                }

                //添加新的一行
                printerLineList.addAll(print1Item1OrderDetailWithSetMenu(item, zh, notPrintItemName));

                //打印完菜品名和细节，再空一行
                if (config.kitchenReceiptSpacing() && isNotEmpty(item.getItemDetailList())) {
                    printerLineList.add(printerClient.emptyLine());
                }
            }
        }

        printerClient.removeLastEmptyLine(printerLineList);
        return printerLineList;
    }

    /**
     * 打印订单规格项, 整个订单打印
     *
     * @param itemDetailList
     * @return
     */
    private List<PrinterLine> printItemDetail_Kitchen(List<ItemDetail> itemDetailList, boolean zh) {
        logger.info("add item detail {} ", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        itemDetailList.stream().forEach(itemDetail -> {
            if (!getBoolean(itemDetail.getVerticalPrint())) {
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();

                List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    return nameAndPriceName;
                }).collect(Collectors.toList());


                String content = StringUtils.join(nameList, ", ");

                if (zh) {
                    //添加14位，变成双倍后就是8位空格
                    String preSpace = printerClient.generateSpace(6 + 2);
                    List<String> contentList = printerClient.getStringList(content, LINE_LENGTH / 2 - 6 - 2, zh);
                    contentList = contentList.stream().map(oneContent -> {
                        logger.info("one content is {}", oneContent);
                        return preSpace + oneContent.trim();
                    }).collect(Collectors.toList());

                    content = StringUtils.join(contentList, "<BR>");
                } else {
                    //英文的话就是后面10位空格
                    String preSpace = printerClient.generateSpace(6 + 2);
                    List<String> contentList = printerClient.getStringList(content, LINE_LENGTH / 2 - 6 - 2, zh);
                    contentList = contentList.stream().map(oneContent -> {
                        logger.info("one content is {}", oneContent);
                        return preSpace + oneContent.trim();
                    }).collect(Collectors.toList());

                    content = StringUtils.join(contentList, "<BR>");
                }

                content = printerClient.appendDouble(content);

                printerItem.setContent(content);

                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            } else {
                //竖排打印
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();

                //添加14位，变成双倍后就是8位空格
                List<String> printContent = itemDetail.getNameAndPriceList().stream().map(detail -> {
                    String content = langService.getNameAndPriceName(detail, zh);
                    String preSpace = printerClient.generateSpace(6 + 2);
                    List<String> contentList = printerClient.getStringList(content, LINE_LENGTH / 2 - 6 - 2, zh);
                    contentList = contentList.stream().map(oneContent -> {
                        logger.info("one content is {}", oneContent);
                        return preSpace + oneContent.trim();
                    }).collect(Collectors.toList());

                    content = StringUtils.join(contentList, "<BR>");

                    return content;
                }).collect(Collectors.toList());

                String content = StringUtils.join(printContent, "<BR>");
                content = printerClient.appendDouble(content);

                printerItem.setContent(content);

                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            }

            if (config.kitchenReceiptSpacing()) {
                printerLineList.add(printerClient.emptyLine());
            }
        });


        return printerLineList;
    }

    /**
     * 发送厨房时，打印套餐格式
     *
     * @param orderItem
     * @param zh
     * @return
     */
    public List<PrinterLine> printerSetMenuWhenSendToKitchen(OrderItem orderItem, boolean zh, boolean notPrintItemName, boolean addSetMenuItemTakeoutFlag) throws Exception {
        logger.info("print set menu order item {}", orderItem.getId());
        List<PrinterLine> printerLineList = new ArrayList<>();

        //中英文同时加8个空格
        int spaceSize = 8;

        boolean firstItem = true;
        for (SetMenuOneItem setMenuOneItem : orderItem.getSetMenuOneItemList()) {
            for (Item item : getList(setMenuOneItem.getItemList())) {
                if (getLong(item.getId()) == 0L) {
                    continue;
                }

                //添加名称,单独一行
                Item itemInDb = ItemService.getInstance().findItem(item.getId());

                //如果是第一个菜，并且不打印套餐名，那么第一个菜的名称不打印
                if (!(firstItem && notPrintItemName)) {
                    String itemName = CommonPrintService.getInstance().getItemPrintName(itemInDb, zh);

                    //如果需要添加外卖标记，则添加外卖标记
                    if (addSetMenuItemTakeoutFlag) {
                        itemName = String.format("%s(%s)", itemName, config.label_take_out(zh));
                    }

                    //依次换行打印
                    List<String> itemNameList = printerClient.getStringList(itemName, (LINE_LENGTH) / 2 - spaceSize, zh);

                    for (int i = 0; i < itemNameList.size(); i++) {
                        String name = itemNameList.get(i);
                        PrinterLine detailNameLine = new PrinterLine();
                        detailNameLine.setDirect(true);
                        String nameContent = printerClient.generateSpace(spaceSize) + name;

                        //如果数量超过一份的话，在末尾加上  *数量
                        if (i == itemNameList.size() - 1) {
                            nameContent = CommonPrintService.getInstance().getItemNameWithCount(nameContent, item);
                        }

                        nameContent = printerClient.appendDouble(nameContent);
                        PrinterItem detailNamePrinterItem = new PrinterItem();
                        detailNamePrinterItem.setDoubleShow(true);
                        detailNamePrinterItem.setContent(nameContent);
                        detailNameLine.add(detailNamePrinterItem);
                        printerLineList.add(detailNameLine);
                    }
                }
                if (config.kitchenReceiptSpacing()) {
                    printerLineList.add(printerClient.emptyLine());
                }

                firstItem = false;

                //再添加细节
                printerLineList.addAll(printItemDetail_SetMenu_Kitchen(item, zh));
            }
        }

        return printerLineList;
    }


    /**
     * 打印订单规格项, 整个订单打印
     *
     * @param item
     * @return
     */
    private List<PrinterLine> printItemDetail_SetMenu_Kitchen(Item item, boolean zh) {
        List<ItemDetail> itemDetailList = getList(item.getItemDetailList());
        logger.info("add item detail {} ", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        for (ItemDetail itemDetail : getList(itemDetailList)) {
            if (!getBoolean(itemDetail.getVerticalPrint())) {
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();

                List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    return nameAndPriceName;
                }).collect(Collectors.toList());

                String content = "---" + StringUtils.join(nameList, ", ");

                int spaceSize = 0;

                if (zh) {
                    //加6个空格，也就是3个字的间隔
                    spaceSize = 6 + 2;
                } else {
                    //英文的话就是后面10位空格
                    spaceSize = 6 + 4;
                }

                //添加14位，变成双倍后就是8位空格
                String preSpace = printerClient.generateSpace(spaceSize);
                List<String> contentList = printerClient.getStringList(content, LINE_LENGTH / 2 - spaceSize, zh);
                contentList = contentList.stream().map(oneContent -> {
                    logger.info("one content is {}", oneContent);
                    return preSpace + oneContent.trim();
                }).collect(Collectors.toList());

                content = StringUtils.join(contentList, "<BR>");

                content = printerClient.appendDouble(content);

                printerItem.setContent(content);

                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            } else {
                //竖排打印
                PrinterLine printerLine = new PrinterLine();
                printerLine.setDirect(true);
                PrinterItem printerItem = new PrinterItem();

                int spaceSize = 0;

                if (zh) {
                    //加6个空格，也就是3个字的间隔
                    spaceSize = 6 + 2;
                } else {
                    //英文的话就是后面10位空格
                    spaceSize = 6 + 4;
                }

                final int spaceSizeFinal = spaceSize;

                List<String> printContentList = itemDetail.getNameAndPriceList().stream().flatMap(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    String content = "---" + nameAndPriceName;

                    //添加14位，变成双倍后就是8位空格
                    String preSpace = printerClient.generateSpace(spaceSizeFinal);
                    List<String> contentList = printerClient.getStringList(content, LINE_LENGTH / 2 - spaceSizeFinal, zh);
                    contentList = contentList.stream().map(oneContent -> {
                        logger.info("one content is {}", oneContent);
                        return preSpace + oneContent.trim();
                    }).collect(Collectors.toList());

                    return contentList.stream();
                }).collect(Collectors.toList());


                String content = StringUtils.join(printContentList, "<BR>");

                content = printerClient.appendDouble(content);

                printerItem.setContent(content);

                printerLine.add(printerItem);
                printerLineList.add(printerLine);
            }

            if (config.kitchenReceiptSpacing()) {
                printerLineList.add(printerClient.emptyLine());
            }
        }


        return printerLineList;
    }


    /**
     * 一菜一单的套餐打印
     *
     * @param item
     * @param zh
     * @return
     */
    private List<PrinterLine> print1Item1OrderDetailWithSetMenu(Item item, boolean zh, boolean notPrintItemName) throws Exception {
        List<ItemDetail> itemDetailList = item.getItemDetailList();
        logger.info("add item detail {} in one item one order", StringUtils.join(itemDetailList, ","));
        List<PrinterLine> printerLineList = new ArrayList<>();

        if (itemDetailList == null) {
            return printerLineList;
        }

        int prefixSpaceSize = getPrefixSpaceSize(notPrintItemName);

        itemDetailList.stream().forEach(itemDetail -> {
            if (!getBoolean(itemDetail.getVerticalPrint())) {
                PrinterLine printerLine = new PrinterLine();

                PrinterItem printerItem = new PrinterItem();
                List<String> nameList = itemDetail.getNameAndPriceList().stream().map(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);
                    return nameAndPriceName;
                }).collect(Collectors.toList());

                //加6个空格，也就是3个字的间隔
                String itemDetailContent = "---" + StringUtils.join(nameList, ", ");

                //每个细节占用的空格数
                int oneItemDetailLength = (LINE_LENGTH / 2 - prefixSpaceSize);
                List<String> detailContentList = printerClient.getStringList(itemDetailContent, oneItemDetailLength, zh);

                List<String> contentList = detailContentList.stream().map(oneDetailContent -> {
                    logger.info("oneDetailContent is {}", oneDetailContent.trim());
                    //空6个空格,3个汉字的距离
                    return printerClient.generateSpace(prefixSpaceSize) + oneDetailContent.trim();
                }).collect(Collectors.toList());

                String content = StringUtils.join(contentList, "<BR>");
                content = printerClient.appendDouble(content);
                printerItem.setContent(content);
                printerLine.add(printerItem);

                printerLineList.add(printerLine);
            } else {
                //竖排打印
                PrinterLine printerLine = new PrinterLine();

                PrinterItem printerItem = new PrinterItem();
                List<String> printContentList = itemDetail.getNameAndPriceList().stream().flatMap(detail -> {
                    String nameAndPriceName = langService.getNameAndPriceName(detail, zh);

                    //加6个空格，也就是3个字的间隔
                    String itemDetailContent = "---" + nameAndPriceName;

                    //每个细节占用的空格数
                    int oneItemDetailLength = (LINE_LENGTH / 2 - prefixSpaceSize);
                    List<String> detailContentList = printerClient.getStringList(itemDetailContent, oneItemDetailLength, zh);

                    List<String> contentList = detailContentList.stream().map(oneDetailContent -> {
                        logger.info("oneDetailContent is {}", oneDetailContent.trim());
                        //空6个空格,3个汉字的距离
                        return printerClient.generateSpace(prefixSpaceSize) + oneDetailContent.trim();
                    }).collect(Collectors.toList());

                    return contentList.stream();
                }).collect(Collectors.toList());

                String content = StringUtils.join(printContentList, "<BR>");
                content = printerClient.appendDouble(content);
                printerItem.setContent(content);
                printerLine.add(printerItem);

                printerLineList.add(printerLine);

                if (config.kitchenReceiptSpacing()) {
                    printerLineList.add(printerClient.emptyLine());
                }

            }

        });

        printerClient.removeLastEmptyLine(printerLineList);
        return printerLineList;
    }

    private int getPrefixSpaceSize(boolean notPrintItemName) {
        int prefixSpaceSize = 4;

        if (notPrintItemName) {
            prefixSpaceSize = 0;
        }
        return prefixSpaceSize;
    }

    /**
     * 服务员端如果对单个菜品或者套餐作为备注，那么这个备注将作为最后一个细节（如果是菜品的话，就是细节）或者菜品发送到厨房（如果是套餐的话，就作为套餐内所有菜的一个细节）
     *
     * @param printerOrder
     */
    public void addRemarks(Order printerOrder) {
        List<OrderItem> orderItemDetailList = printerOrder.getOrderItemDetailList();
        for (OrderItem orderItem : orderItemDetailList) {
            //没有备注，不处理
            if (isEmpty(orderItem.getRemarks())) {
                continue;
            }

            if (!getBoolean(orderItem.getSetMenu())) {
                logger.info("normal item add remarks");
                List<ItemDetail> itemDetailList = getList(orderItem.getItemDetailList());
                addRemartksToItemDetail(orderItem, itemDetailList);
                orderItem.setItemDetailList(itemDetailList);
            } else {
                List<SetMenuOneItem> setMenuOneItemList = getList(orderItem.getSetMenuOneItemList());
                for (SetMenuOneItem setMenuOneItem : setMenuOneItemList) {
                    List<Item> itemList = setMenuOneItem.getItemList();
                    for (Item item : itemList) {
                        if (getLong(item.getId()) <= 0) {
                            continue;
                        }

                        List<ItemDetail> itemDetailList = getList(item.getItemDetailList());
                        addRemartksToItemDetail(orderItem, itemDetailList);
                        item.setItemDetailList(itemDetailList);
                    }
                }
            }

        }
    }

    private void addRemartksToItemDetail(OrderItem orderItem, List<ItemDetail> itemDetailList) {
        ItemDetail itemDetail = new ItemDetail();
        itemDetail.setName_zh(orderItem.getRemarks());
        itemDetail.setName_en(orderItem.getRemarks());
        NameAndPrice nameAndPrice = new NameAndPrice();
        nameAndPrice.setName_zh(orderItem.getRemarks());
        nameAndPrice.setName_en(orderItem.getRemarks());
        itemDetail.setNameAndPriceList(Arrays.asList(nameAndPrice));
        itemDetailList.add(itemDetail);
    }
}
